package JoReg

type NfaManager struct {
	tokenSlc    []Token
	reg         string
	tokenIndex  int
	stateIndex  int
	startNfaPtr *Nfa
	tailNfaPtr  *Nfa
}

func MakeNfaManager(reg string) *NfaManager {
	nfaManagerPtr := &NfaManager{}

	charSlc := []byte(reg)
	tokenSlc := make([]Token, 0)
	var token Token
	for _, char := range charSlc {
		switch char {
		case SLASH:
			token = NewSlashToken()
		case BACKSLASH:
			token = NewMakeBackslashToken()
		case 48, 49, 50, 51, 52, 53, 54, 55, 56, 57:
			token = NewNumberToken(char)
		case DOLLAR:
			token = NewDollarToken()
		case DOT:
			token = NewDotToken()
		case ASTERISK:
			token = NewAsteriskToken()
		case PLUS:
			token = NewPlusToken()
		case OR:
			token = NewOrToken()
		case OPTION:
			token = NewOptionToken()
		case OPEN_PAREN:
			token = NewOpenParenToken()
		case CLOSE_PAREN:
			token = NewCloseParenToken()
		case OPEN_BRACKET:
			token = NewOpenBracketToken()
		case CLOSE_BRACKET:
			token = NewCloseBracketToken()
		case OPEN_CURLY:
			token = NewOpenCurlyToken()
		case CLOSE_CURLY:
			token = NewCloseCurlyToken()
		case CARET:
			token = NewCaretToken()
		case DASH:
			token = NewDashToken()
		default:
			token = NewCharacterToken(char)
		}
		tokenSlc = append(tokenSlc, token)
	}
	nfaManagerPtr.tokenSlc = tokenSlc
	nfaManagerPtr.tokenIndex = 0
	nfaManagerPtr.stateIndex = 0
	return nfaManagerPtr
}

func (this *NfaManager) parse() {
	// this.parseSingleCharacter()
	this.parseDot()
	// 状态打印
	this.printNfa(this.startNfaPtr)
}

func (this *NfaManager) lookahead() Token {
	if this.tokenIndex+1 >= len(this.tokenSlc) {
		return NewEosToken()
	}
	return this.tokenSlc[this.tokenIndex+1]
}

func (this *NfaManager) advance() Token {
	if this.tokenIndex >= len(this.tokenSlc) {
		return NewEosToken()
	}
	this.tokenIndex++
	return this.tokenSlc[this.tokenIndex-1]
}

func (this *NfaManager) curToken() Token {
	if this.tokenIndex >= len(this.tokenSlc) {
		return NewEosToken()
	}
	return this.tokenSlc[this.tokenIndex]
}

// 整个表达式解析
func (this *NfaManager) parseExpr() {
	this.parseExpr_()
	for {
		if this.matchToken(OR) {
			this.advance()
			oldStartNfaPtr := this.startNfaPtr
			oldTailNfaPtr := this.tailNfaPtr
			this.startNfaPtr = nil
			this.tailNfaPtr = nil
			this.parseExpr_()
			newStartNfaPtr := MakeNfa(this)
			newTailNfaPtr := MakeNfa(this)
			newStartNfaPtr.upPtr = oldStartNfaPtr
			newStartNfaPtr.nextPtr = this.startNfaPtr
			oldTailNfaPtr.nextPtr = newTailNfaPtr
			this.tailNfaPtr.nextPtr = newTailNfaPtr
			this.startNfaPtr = newStartNfaPtr
			this.tailNfaPtr = newTailNfaPtr
		} else {
			break
		}
	}
}

func (this *NfaManager) parseParen() bool {
	if !this.matchToken(OPEN_PAREN) {
		return false
	}
	this.advance()
	// 解析括号里的表达式
	this.parseExpr()
	if !this.matchToken(CLOSE_PAREN) {
		return false
	} else {
		this.advance()
		return true
	}
}

func (this *NfaManager) parseExpr_() {
	if this.checkFactorStart() {
		// 除了下面符号，新的factor=>term*|term+|term?
		// 1.闭包符*?+
		// 2.配对的结束符)]}
		// 3.开始符^
		// 4.终止符$
		// 5.并联符|
		this.parseFactor()
	}
	for {
		if this.checkFactorStart() {
			oldStartNfaPtr := this.startNfaPtr
			oldTailNfaPtr := this.tailNfaPtr
			this.startNfaPtr = nil
			this.tailNfaPtr = nil
			this.parseFactor()
			// 多个factor连接
			oldTailNfaPtr.nextPtr = this.startNfaPtr
			this.startNfaPtr = oldStartNfaPtr
		} else {
			break
		}
	}
}

// parseFactor factor=> term?|term*|term+
// 闭包符:*+?
func (this *NfaManager) parseFactor() {
	this.parseTerm()
	handlerFlag := this.parseOption()
	if !handlerFlag {
		handlerFlag = this.parseAsterisk()
	}
	if !handlerFlag {
		this.parsePlus()
	}
}

// parseTerm term=> (expr)|A|[]|.|\|0
func (this *NfaManager) parseTerm() {
	handlerFlag := this.parseParen()
	if !handlerFlag {
		// 解析单个字符
		handlerFlag = this.parseSingleCharacter()
	}
	if !handlerFlag {
		// 解析数字
		handlerFlag = this.parseSingleNumber()
	}
	if !handlerFlag {
		// 解析.
		handlerFlag = this.parseDot()
	}
	if !handlerFlag {
		// 解析[]
		handlerFlag = this.parseCharacterSet()
	}
	if !handlerFlag {
		// 解析\
		this.parseBackslash()
	}
}

// parseSingleCharacter 单个字符解析
func (this *NfaManager) parseSingleCharacter() bool {
	if !this.matchToken(CHARACTER) {
		return false
	}
	nfaPtr := MakeNfa(this)
	nfaPtr.putEdge(this.tokenSlc[this.tokenIndex].lexeme)
	nextNfaPtr := MakeNfa(this)
	nfaPtr.nextPtr = nextNfaPtr
	this.startNfaPtr = nfaPtr
	this.tailNfaPtr = nextNfaPtr
	this.advance()
	return true
}

// parseSingleNumber 单个数字解析
func (this *NfaManager) parseSingleNumber() bool {
	if !this.matchToken(NUMBER) {
		return false
	}
	nfaPtr := MakeNfa(this)
	nfaPtr.putEdge(this.tokenSlc[this.tokenIndex].lexeme)
	nextNfaPtr := MakeNfa(this)
	nfaPtr.nextPtr = nextNfaPtr
	this.startNfaPtr = nfaPtr
	this.tailNfaPtr = nfaPtr
	this.advance()
	return true
}

// parseDot .:点解析
func (this *NfaManager) parseDot() bool {
	if !this.matchToken(DOT) {
		return false
	}
	nfaPtr := MakeNfa(this)
	nfaPtr.putEdge('\n')
	nfaPtr.putEdge('\r')
	nfaPtr.Complement()
	nextNfaPtr := MakeNfa(this)
	nfaPtr.nextPtr = nextNfaPtr
	this.startNfaPtr = nfaPtr
	this.tailNfaPtr = nextNfaPtr
	this.advance()
	return true
}

// parseCharacterSet []:字符集合解析
func (this *NfaManager) parseCharacterSet() bool {
	if !this.matchToken(OPEN_BRACKET) {
		return false
	}
	// 跳过[
	this.advance()
	nfaPtr := MakeNfa(this)
	if this.lookahead().token == DASH {
		openAscii := this.tokenSlc[this.tokenIndex].lexeme
		this.advance()
		var closeAscii = byte(0)
		closeFlag := false
		for {
			if this.matchToken(CLOSE_BRACKET) {
				this.advance()
				break
			}
			if this.matchToken(DASH) {
				closeFlag = true
				// 跳过-
				this.advance()
			}
			if closeFlag {
				closeAscii = this.tokenSlc[this.tokenIndex].lexeme
				for i := openAscii; i <= closeAscii; i++ {
					nfaPtr.putEdge(i)
				}
				closeFlag = false
				this.advance()
			} else {
				openAscii = this.tokenSlc[this.tokenIndex].lexeme
				this.advance()
			}
		}
	} else {
		for {
			if this.matchToken(CLOSE_BRACKET) {
				this.advance()
				break
			}
			nfaPtr.putEdge(this.tokenSlc[this.tokenIndex].lexeme)
			this.advance()
		}
	}
	nextNfaPtr := MakeNfa(this)
	nfaPtr.nextPtr = nextNfaPtr
	this.startNfaPtr = nfaPtr
	this.tailNfaPtr = nextNfaPtr
	return true
}

// parseAsterisk *:{0,N} 星号解析
func (this *NfaManager) parseAsterisk() bool {
	if !this.matchToken(ASTERISK) {
		return false
	}
	newStartNfaPtr := MakeNfa(this)
	newTailNfaPtr := MakeNfa(this)
	newStartNfaPtr.upPtr = this.startNfaPtr
	// N次
	this.tailNfaPtr.upPtr = this.startNfaPtr
	this.tailNfaPtr.nextPtr = newTailNfaPtr
	// 0次
	newStartNfaPtr.nextPtr = newTailNfaPtr
	this.startNfaPtr = newStartNfaPtr
	this.tailNfaPtr = newTailNfaPtr
	this.advance()
	return true
}

// parsePlus +:{1,N} 加号解析
func (this *NfaManager) parsePlus() bool {
	if !this.matchToken(PLUS) {
		return false
	}
	newStartNfaPtr := MakeNfa(this)
	newTailNfaPtr := MakeNfa(this)
	// N次
	newStartNfaPtr.upPtr = this.startNfaPtr
	this.tailNfaPtr.upPtr = this.startNfaPtr
	this.tailNfaPtr.nextPtr = newTailNfaPtr
	this.startNfaPtr = newStartNfaPtr
	this.tailNfaPtr = newTailNfaPtr
	this.advance()
	return true
}

// parseOption ?:{0,1} 问号解析
func (this *NfaManager) parseOption() bool {
	if !this.matchToken(OPTION) {
		return false
	}
	newStartNfaPtr := MakeNfa(this)
	newTailNfaPtr := MakeNfa(this)
	this.tailNfaPtr.nextPtr = newTailNfaPtr
	newStartNfaPtr.upPtr = this.startNfaPtr
	// 0次
	newStartNfaPtr.nextPtr = newTailNfaPtr
	this.startNfaPtr = newStartNfaPtr
	this.tailNfaPtr = newTailNfaPtr
	this.advance()
	return true
}

// parseBackslash \:反斜杠解析
func (this *NfaManager) parseBackslash() bool {
	if !this.matchToken(BACKSLASH) {
		return false
	}
	complementFlag := false
	// 跳过\
	this.advance()
	nfaPtr := MakeNfa(this)
	nextNfaPtr := MakeNfa(this)
	nfaPtr.nextPtr = nextNfaPtr
	this.startNfaPtr = nfaPtr
	this.tailNfaPtr = nextNfaPtr
	// \下一个token
	curToken := this.curToken()
	switch curToken.lexeme {
	case 'd':
		nfaPtr.putNumberEdge()
	case 'D':
		nfaPtr.putNumberEdge()
		complementFlag = true
	case 'w':
		nfaPtr.putLowerEdge()
		nfaPtr.putUpperEdge()
	case 'W':
		nfaPtr.putLowerEdge()
		nfaPtr.putUpperEdge()
		complementFlag = true
	case 's':
		nfaPtr.putBlankCharEdge()
	case 'S':
		nfaPtr.putBlankCharEdge()
		complementFlag = true
	default:
		// 转义字符
		nfaPtr.putEdge(curToken.lexeme)
	}
	if complementFlag {
		nfaPtr.Complement()
	}
	this.advance()
	return true
}

func (this *NfaManager) checkFactorStart() bool {
	if this.tokenIndex >= len(this.tokenSlc) {
		return false
	}
	token := this.tokenSlc[this.tokenIndex].token
	switch token {
	case CLOSE_PAREN, CLOSE_BRACKET, CLOSE_CURLY:
		return false
	case OR:
		return false
	case CARET, DOLLAR:
		return false
	case ASTERISK, PLUS, OPTION:
		return false
	}
	return true
}

func (this *NfaManager) matchToken(matchToken byte) bool {
	if this.tokenIndex >= len(this.tokenSlc) {
		return false
	}
	curToken := this.tokenSlc[this.tokenIndex]
	if curToken.token == matchToken {
		return true
	} else {
		return false
	}
}
